package bai.myworld.common.utils;

import bai.myworld.config.JwtConfig;
import bai.myworld.exception.ErrorCode;
import bai.myworld.exception.BusinessException;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.sun.tools.javac.Main;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.Date;
import java.util.concurrent.TimeUnit;


/**
 * JWT工具类（基于Auth0-java-jwt实现）
 * 注意：生产环境必须配合密钥管理方案（如KMS/配置中心）使用
 */
@Component
public class JwtUtil {
// 获取日志记录器
    private static final Logger log = LogManager.getLogger(JwtUtil.class); // 修复日志记录器
    private static Algorithm algorithm = null;
    private final long expirationMs;


    // 唯一构造器（Spring注入）
    public JwtUtil(JwtConfig jwtConfig) {
        this.algorithm = Algorithm.HMAC256(jwtConfig.getSecret());
        this.expirationMs = 7 * 24 * 60 * 60 * 1000L; // 移出常量区
        log.info("JWT算法初始化完成，使用密钥长度：{}", jwtConfig.getSecret().length());
    }
    private static final long EXPIRATION_MS = 7 * 24 * 60 * 60 * 1000; // 常量保持static

    // 构造器注入
//    public JwtUtil(JwtConfig jwtConfig) {
//        this.algorithm = Algorithm.HMAC256(jwtConfig.getSecret());
//        log.info("JWT算法初始化完成，使用{}算法", algorithm.getName());
//    }

    /**
     * 生成JWT Token
     * @param userId 用户ID（建议不要直接使用敏感信息）
     * @param tokenVersion Token版本号（用于强制失效，如修改密码后递增）
     * @return 签名的Token字符串
     *
     * 安全提示：
     * 1. 不要在Payload中存放敏感信息（如密码）
     * 2. 建议添加issuer(签发者)和audience(受众)声明
     */

    // 新增多时间单位支持的方法
    public static String generateToken(Long userId, int tokenVersion, long duration, TimeUnit timeUnit) {
        long expirationMs = timeUnit.toMillis(duration); // toMillis: 从一种时间单位转换为毫秒
        return JWT.create()
                .withClaim("userId", userId) // 添加自定义声明
                .withClaim("version", tokenVersion)
                .withIssuedAt(new Date()) // 设置 JWT 的签发时间
                .withExpiresAt(new Date(System.currentTimeMillis() + expirationMs)) // 设置 JWT 过期时间
                .sign(algorithm); // 进行 ALGORITHM算法 签名
    }

    /**
     * 验证Token有效性（包含签名和版本号检查）
     * @param token 待验证的Token
     * @param currentVersion 当前最新版本号（用于防止旧Token有效）
     * @return 是否验证通过
     *
     * 注意：此方法会同时验证：
     * 1. 签名是否被篡改
     * 2. Token是否过期
     * 3. 版本号是否匹配
     */
    public  boolean validateToken(String token, int currentVersion) {
        try {
            DecodedJWT jwt = JWT.require(algorithm) // 指定 JWT 的签名算法
                    .build() // 完成 JWT 验证器的配置，并准备进行 JWT 的验证
                    .verify(token); // 自动验证签名和过期时间

            // 检查业务版本号（用于实现主动失效）
            return jwt.getClaim("version").asInt() == currentVersion; // 获取 JWT 中的自定义声明 version, 并转换为 int 类型
        }catch (TokenExpiredException e) {
            log.warn("Token过期: {}", token);
            throw new BusinessException(ErrorCode.TOKEN_EXPIRED);
        } catch (JWTVerificationException e) {
            log.warn("Token篡改: {}", token);
            throw new BusinessException(ErrorCode.TOKEN_TAMPERED);
        }
    }

    /**
     * 从Token中解析用户ID（不验证签名，仅用于非安全场景）
     * @param token 待解析的Token
     * @return 用户ID
     *
     * 安全警告：
     * 1. 此方法不会验证签名和过期时间！仅适用于已通过validateToken验证的场景
     * 2. 如需安全解析，请使用 validateToken + getVerifiedUserId 组合
     */
    public static Long getUserIdFromToken(String token) {
        DecodedJWT jwt = JWT.decode(token); // 注意：此处仅解码，不验证
        return jwt.getClaim("userId").asLong();
    }

    // ---------- 以下是安全增强方法（推荐）----------

    /**
     * 安全获取用户ID（先验证再解析）
     * @return 如果验证失败返回null
     */
    public  Long getVerifiedUserId(String token, int currentVersion) {
        if (!validateToken(token, currentVersion)) {
            return null;
        }
        return JWT.decode(token).getClaim("userId").asLong();
    }

    /**
     * 获取Token剩余有效期（秒）
     * @return 剩余秒数（已过期返回负数）
     */
    public  long getRemainingSeconds(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return (jwt.getExpiresAt().getTime() - System.currentTimeMillis()) / 1000;
    }

    /**
     * 获取Token过期时间
     * @param token JWT令牌
     * @return 过期时间的Date对象（未验证签名）
     *
     * 注意：此方法仅解码不验证，适合已通过validateToken的场景
     */
    public static Date getExpiryDate(String token) {
        return JWT.decode(token).getExpiresAt();
    }

    /**
     * 安全获取过期时间（先验证再解析）
     * @return 如果验证失败返回null
     */
    public  Date getVerifiedExpiryDate(String token, int currentVersion) {
        if (!validateToken(token, currentVersion)) {
            return null;
        }
        return JWT.decode(token).getExpiresAt();
    }

}
